(* 定义一个 module  *)
module ListStack = struct
  let empty = []
  let is_empty s = (s = [])

  let push x s = x :: s

  let peek = function
    | [] -> failwith "Empty"
    | x::_ -> x

  let pop = function
    | [] -> failwith "Empty"
    | _::xs -> xs
end

module ListStackTest = struct
  let _ =
    let list = ListStack.empty in
    ListStack.push 1 list

  let _ =
    let open ListStack in (* you can open module locally *)
    let list = empty in
    push 1 list

  let _ =
    ListStack.( (* Module.() is a short version for open module *)
      let list = empty in
      push 1 list
    )
end

(* 定义一个module 签名 *)
module type Stack = sig
  type 'a stack
  val empty    : 'a stack
  val is_empty : 'a stack -> bool
  val push     : 'a -> 'a stack -> 'a stack
  val peek     : 'a stack -> 'a
  val pop      : 'a stack -> 'a stack
  (* format make repl print beautiful and helpful *)
  val format : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a stack -> unit
end

module ListStackWithSig : Stack = struct
  type 'a stack = 'a list

  let empty = []
  let is_empty s = (s = [])

  let push x s = x :: s

  let peek = function
    | [] -> failwith "Empty"
    | x::_ -> x

  let pop = function
    | [] -> failwith "Empty"
    | _::xs -> xs

  let format fmt_elt fmt s =
    Format.fprintf fmt "[";
    List.iter (fun elt -> Format.fprintf fmt "%a; " fmt_elt elt) s;
    Format.fprintf fmt "]"
end
